/* hal_dma.h */
#ifndef __HAL_DMA_H__
#define __HAL_DMA_H__

#include "fsl_common.h"

#define DMA_CHANNEL_COUNT  30U

/* 全局中断标志位，为DMA_GetGlobalInterruptStatusFlags函数的返回值 */
enum DMA_GlobalInterruptFlags_T
{
    eDMA_GlobalInterruptFlag_AnyEvent = DMA_INTSTAT_ACTIVEINT_MASK,
    eDMA_GlobalInterruptFlag_Error = DMA_INTSTAT_ACTIVEERRINT_MASK,
};

/* 指定DMA捕获硬件触发信号类型 */
typedef enum
{
    eDMA_HardwareTriggerMode_FallingEdge = 0U,
    eDMA_HardwareTriggerMode_RisingEdge = 1U,
    eDMA_HardwareTriggerMode_LowLevel = 2U,
    eDMA_HardwareTriggerMode_HighLevel = 3U,
} DMA_HardwareTriggerMode_T;

/* 指定传输位宽 */
typedef enum
{
    eDMA_TransferWidth_8b = 0U,
    eDMA_TransferWidth_16b = 1U,
    eDMA_TransferWidth_32b = 2U,
} DMA_TransferWidth_T;

/* 指定传输步长 */
typedef enum
{
    eDMA_TransferAddressIncrease_NoChange = 0U,
    eDMA_TransferAddressIncrease_1xWidth = 1U,
    eDMA_TransferAddressIncrease_2xWidth = 2U,
    eDMA_TransferAddressIncrease_4xWidth = 3U,
} DMA_TransferAddressIncrease_T;

/* 块传输配置属性 */
typedef struct
{
    uint32_t BurstTransferSizePower; /* 块传输数据大小的指数 */
    bool EnableSourceBurstWrap;
    bool EnableDestBurstWrap;
} DMA_BurstTransferConfig_T;

/* DMA传输通道的静态属性
 * 主要是配置触发信号
 */
typedef struct
{
    bool EnablePeripheralRequest; /*!< 外设请求是来自于外设通信引擎的DMA触发信号。
                                       实际上这里设定的是DMA搬运数据的模式：
                                       - 当PeripheralRequest功能关闭时，DMA通道会在触发开关打开之后立即搬运数据。
                                       - 当PeripheralRequest功能打开时，DMA通道将会在外设的驱动下每次只搬运一个数据，
                                         但同时还需要地址递增设定的配合
                                        */
    bool EnableHardwareTrigger; /*!< 硬件触发开关是接收外设请求的门控开关：
                                    - 若启用硬件触发，则触发源从INPUT MUX中选择，一旦硬件触发信号到来，则立即开放DMA通道的Request输入
                                    - 软件触发总是可用的
                                    */
    DMA_HardwareTriggerMode_T HardwareTriggerMode; /*!< 捕获硬件触发信号的模式 */
    DMA_BurstTransferConfig_T *BurstTransferConfig; /*! 配置块传输结构体的指针，若为NULL，则不启用块传输功能 */
    uint32_t ChannelPriority; /*!< 通道优先级，0最高，7最低 */
} DMA_ChannelConfig_T;

/* XFERCFG.
 * 每个传输符对应的传输配置字
 */
typedef struct
{
    /* XFERCFG. */
    bool EnableValidNow; /*!< Or等待软件设定SETVALID0 */
    bool EnableReloadNextDescriptor; /*!< 当启用Reload功能后，重新载入新的传输描述符时，保留当前XFERCFG寄存器的设定，
                                          否则将使用传输描述符结构中的xfercfg字段设定XFERCFG寄存器。
                                          只有在ping-pong传输模式下常用RELOAD功能，否则在其它模式下，后续传输无法自动更新传输配置 */
    bool EnableTriggerBySoftwareNow; /*!< 立即通过软件启动Trigger，否则仍需要额外软件Trigger或硬件触发后才能响应外部Request */
    bool EnableAutoClearTrigger; /*!< 当消耗掉当前的传输描述符之后，自动清除Trigger已经被触发的状态。
                                      在一次性连续传输多个描述符时，关闭此功能，可以仅被触发一次的情况下，多个连续的描述符连续被触发传输数据 */
    bool EnableFlagOnInterruptA; /* 当消耗掉当前传输描述符后，触发interrupt A. */
    bool EnableFlagOnInterruptB; /* 当消耗掉当前传输描述符后，触发interrupt B. */
    DMA_TransferWidth_T TransferWidth; /* 传输宽度 */
    DMA_TransferAddressIncrease_T TransferSourceAddressIncrease; /* 源地址增加步长 */
    DMA_TransferAddressIncrease_T TransferDestAddressIncrease;   /* 目的地址增加步长 */
    uint32_t TransferCount; /* 传输次数，而不是传输字节数 */
} DMA_TransferConfig_T;

#pragma anon_unions

/* DMA传输描述符
 * DMA硬件要求软件在内存中分配的配置数据结构，
 * 虽然是用户在内存中分配的结构体，但效力等同于寄存器。
 */
typedef struct _DMA_TransferDescriptor_T
{
    uint32_t TransferConfigWord; /*!< 传输配置信息 */
    union
    {
        uint32_t SourceEndAddrress;
        uint32_t SourceStartAddress;
    } ;
    union
    {
        uint32_t DestEndAddress;
        uint32_t DestStartAddress;
    } ;
    struct _DMA_TransferDescriptor_T *LinkToNext; /* 下一个DMA描述符的指针 */
} DMA_TransferDescriptor_T;

/* Shared APIs. */
void DMA_Init(DMA_Type *base);
void DMA_Deinit(DMA_Type *base);
uint32_t DMA_GetGlobalInterruptStatusFlags(DMA_Type *base);

/* Common APIs. */
void DMA_EnableChannels(DMA_Type *base, uint32_t channelMask, bool enable);
uint32_t DMA_GetActiveChannels(DMA_Type *base);
uint32_t DMA_GetBusyChannels(DMA_Type *base);
uint32_t DMA_GetErrorChannels(DMA_Type *base);
void DMA_ClearErrorChannels(DMA_Type *base, uint32_t channelMask);
void DMA_EnableChannelsInterrupt(DMA_Type *base, uint32_t channelMask, bool enable);
uint32_t DMA_GetChannelsOnInterruptA(DMA_Type *base);
void DMA_ClearFlagsOnInterruptA(DMA_Type *base, uint32_t channelMask);
uint32_t DMA_GetChannelsOnInterruptB(DMA_Type *base);
void DMA_ClearFlagsOnInterruptB(DMA_Type *base, uint32_t channelMask);
void DMA_DoBypassAutoValidsOfTransferSettingCmd(DMA_Type *base, uint32_t channelMask);
void DMA_DoSoftTriggerCmd(DMA_Type *base, uint32_t channelMask);
void DMA_DoAbortChannels(DMA_Type *base, uint32_t channelMask);

/* Channel APIs. */
void DMA_SetChannelConfig(DMA_Type *base, uint32_t channelIndex, DMA_ChannelConfig_T *config);
uint32_t DMA_CreateTransferConfigWord(DMA_TransferConfig_T *config);
void DMA_SetHeadTransferDescriptor(DMA_Type *base, uint32_t channelIndex, DMA_TransferDescriptor_T *descriptor);
void DMA_AddTransferDescriptor(DMA_Type *base, uint32_t channelIndex, DMA_TransferDescriptor_T *descriptor);
bool DMA_IsChannelDescriptorValid(DMA_Type *base, uint32_t channelIndex);
void DMA_ConvertTransferDescriptor(DMA_TransferDescriptor_T *descriptor);
#endif /* __HAL_DMA_H__ */

